﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using SongSharp.Domain.Objects;

namespace SongSharp.Domain.Data
{
    public class DataManager
    {
        private static DataManager ms_instance;
        private static string ms_dataPath = "";
        private const string LIBRARY_FILE = "library.xml";
        private const string STATE_FILE = "songsharp.xml";
        private XmlSerializer m_librarySerializer;
        private XmlSerializer m_statisticSerializer;
        private XmlSerializer m_songSharpStateSerializer;

        # region Cached items
        private Library m_library;
        private Library Library
        {
            get
            {
                if (m_library == null)
                    m_library = GetLibrary();
                return m_library;
            }
        }
        private SongSharpState m_songSharpState;
        public SongSharpState State
        {
            get
            {
                if (m_songSharpState == null)
                    m_songSharpState = GetSongSharpState();
                return m_songSharpState;
            }
        }
        #endregion

        # region Initialisation
        private DataManager(string dataPath)
        {
            m_librarySerializer = new XmlSerializer(typeof(Library));
            m_statisticSerializer = new XmlSerializer(typeof(TrackStatistic));
            m_songSharpStateSerializer = new XmlSerializer(typeof(SongSharpState));

            ms_dataPath = dataPath;
        }

        public static DataManager Instance
        {
            get
            {
                if (ms_instance == null)
                    throw new InvalidOperationException("Cannot create instance. Set dataPath first using the method 'CreateInstance'.");
                return ms_instance;
            }
        }

        private static bool CanWriteToFolder(string path)
        {
            if (Directory.Exists(path))
            {
                try
                {
                    string folder = Path.Combine(path, Guid.NewGuid().ToString());
                    File.WriteAllText(folder, "This temporary file is created for testing the permissions of the data folder");
                    File.Delete(folder);
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }
            return false;
        }

        public static void CreateInstance(string dataPath)
        {
            if (!DataManager.CanWriteToFolder(dataPath)) 
            {
                dataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "SongSharp");
                if (!Directory.Exists(dataPath))
                    Directory.CreateDirectory(dataPath);
            }

            if (ms_instance == null)
                ms_instance = new DataManager(dataPath);
        }
        #endregion

        public List<Track> Tracks
        {
            get
            {
                return Library.Tracks;
            }
        }

        public List<Playlist> Playlists
        {
            get
            {
                return Library.Playlists;
            }
        }

        public SongSharpState GetSongSharpState()
        {
            SongSharpState s = null;
            XmlTextReader reader = null;

            try
            {
                reader = new XmlTextReader(new FileStream(Path.Combine(ms_dataPath, STATE_FILE),
                    FileMode.Open));
                s = m_songSharpStateSerializer.Deserialize(reader) as SongSharpState;
            }
            catch (Exception)
            {
                s = new SongSharpState();
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }

            return s;
        }

        public void UpdateSongSharpState(SongSharpState state)
        {
            XmlTextWriter writer = new XmlTextWriter(new FileStream(Path.Combine(ms_dataPath, STATE_FILE),
                FileMode.Create), Encoding.UTF8);
            m_songSharpStateSerializer.Serialize(writer, state);

            writer.Close();
        }

        public Library GetLibrary()
        {
            Library l = null;
            XmlTextReader reader = null;

            try
            {
                reader = new XmlTextReader(new FileStream(Path.Combine(ms_dataPath, LIBRARY_FILE),
                    FileMode.Open));
                l = m_librarySerializer.Deserialize(reader) as Library;
            }
            catch (Exception)
            {
                l = new Library();
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }

            return l;
        }

        public void AddTracks(List<Track> tracks)
        {
            Library.Tracks.AddRange(tracks);

            XmlTextWriter writer = new XmlTextWriter(new FileStream(Path.Combine(ms_dataPath, LIBRARY_FILE),
                FileMode.Create), Encoding.UTF8);
            m_librarySerializer.Serialize(writer, Library);

            writer.Close();

            UpdateLibrary();
        }

        public void AddPlaylists(List<Playlist> playlists)
        {
            Library.Playlists.AddRange(playlists);

            XmlTextWriter writer = new XmlTextWriter(new FileStream(Path.Combine(ms_dataPath, LIBRARY_FILE),
                FileMode.Create), Encoding.UTF8);
            m_librarySerializer.Serialize(writer, Library);
            writer.Close();

            UpdateLibrary();
        }

        public void UpdateLibrary()
        {
            m_library = GetLibrary();
        }

        public TrackStatistic GetTrackStatisticByTrackID(string trackID)
        {
            TrackStatistic s = null;
            XmlTextReader reader = null;
            try
            {
                reader = new XmlTextReader(new FileStream(Path.Combine(ms_dataPath, trackID) + ".xml",
                    FileMode.Open));
                s = m_statisticSerializer.Deserialize(reader) as TrackStatistic;
            }
            catch (Exception)
            {
                s = new TrackStatistic();
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }

            return s;
        }

        public void UpdateTrackStatistic(string trackID, TrackStatistic statistic)
        {
            XmlTextWriter writer = new XmlTextWriter(new FileStream(Path.Combine(ms_dataPath, trackID) + ".xml",
                FileMode.Create), Encoding.UTF8);
            m_statisticSerializer.Serialize(writer, statistic);
            writer.Close();
        }


    }
}
